package org.fisco.bcos.evidence.client;

import org.fisco.bcos.evidence.bean.Account;
import org.fisco.bcos.evidence.bean.BcosEvidence;
import org.fisco.bcos.evidence.contract.EvidenceTable;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple4;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple5;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/// 统一存证平台 - 存证合约

/**
 * 注意:
 */
@Service
public class EvidenceTableClient {
    static Logger logger = LoggerFactory.getLogger(EvidenceTableClient.class);

    @Autowired
    private BcosConnnection bcosConnnection;

    @Autowired
    private ShaTestClient shaTestClient;

    @Value("${contract.evidence_table.address}")
    protected String contractAddress;


//    public void setCrypto(ShaTestClient shaTestClient) {
//        this.shaTestClient = shaTestClient;
//    }

//    /**
//     * 2. 构造合约类对象 - 部署合约
//     */
//    public void deploy() {
//        try {
//            EvidenceTable evidenceTable = EvidenceTable.deploy(bcosConnnection.client, bcosConnnection.cryptoKeyPair);
//            System.out.println(" deploy EvidenceTable success, contract address is " + evidenceTable.getContractAddress());
//            contractAddress = evidenceTable.getContractAddress();
//        } catch (Exception e) {
//            System.out.println(" deploy EvidenceTable contract failed, error message is  " + e.getMessage());
//        }
//    }


    /**
     * 3. 接口调用
     * <p>
     * 使用合约对象调用对应的接口，处理返回结果。
     * //insert records
     * function insert(string memory key, string memory owner, string memory data, string memory ehash)
     * public
     * returns (int256)
     */
    public boolean addEvidence(BcosEvidence evidence) {
        try {
            EvidenceTable evidenceTable = EvidenceTable.load(contractAddress, bcosConnnection.client, bcosConnnection.cryptoKeyPair);

            /// 计算 Keccak256 Hash 值
            StringBuilder builder = new StringBuilder();
            builder.append(evidence.getKey()).
                    append(evidence.getOwner()).
                    append(evidence.getData());
            evidence.setEhash(shaTestClient.getKeccak256(builder.toString()));

            logger.info("src=" + builder.toString());
            logger.info("hash=" + evidence.getEhash());

            TransactionReceipt receipt = evidenceTable.insert(
                    evidence.getKey(), evidence.getOwner(),
                    evidence.getData(), evidence.getEhash()
            );

            Tuple1<BigInteger> retOutput = evidenceTable.getInsertOutput(receipt);
            BigInteger ret = retOutput.getValue1();
            System.out.printf("ret =" + ret);

            return (ret.intValue() > 0) ? true : false;
        } catch (Exception e) {
            logger.error(" addEvidence exception, error message is {}", e.getMessage());
            System.out.printf(" addEvidence account failed, error message is %s\n", e.getMessage());
        }
        return false;
    }


    /**
     * 3. 接口调用
     * <p>
     * 使用合约对象调用对应的接口，处理返回结果。
     * //select one
     * function select(string memory key)
     * public
     * view
     * returns (string memory, string memory, string memory, string memory)
     */
    public BcosEvidence getEvidence(String key) {
        BcosEvidence evidence = new BcosEvidence();

        try {
            EvidenceTable evidenceTable = EvidenceTable.load(contractAddress, bcosConnnection.client, bcosConnnection.cryptoKeyPair);
            Tuple4<String, String, String, String> result = evidenceTable.select(key);

            evidence.setKey(result.getValue1());
            evidence.setOwner(result.getValue2());
            evidence.setData(result.getValue3());
            evidence.setEhash(result.getValue4());
        } catch (Exception e) {
            logger.error(" queryEvidenceTableAmount exception, error message is {}", e.getMessage());
            System.out.printf(" query EvidenceTable account failed, error message is %s\n", e.getMessage());
        }
        return evidence;
    }


    /**
     * 3. 接口调用
     * <p>
     * 使用合约对象调用对应的接口，处理返回结果。
     * //select by owner
     * function selectKeysByOwner(string memory owner)
     * public
     * returns (string[] memory)
     */
    public List<BcosEvidence> getEvidencesByOwner(String owner) {
        List<BcosEvidence> evidences = new ArrayList<>();

        try {
            EvidenceTable evidenceTable = EvidenceTable.load(contractAddress, bcosConnnection.client, bcosConnnection.cryptoKeyPair);
            TransactionReceipt receipt = evidenceTable.selectKeysByOwner(owner);
            Tuple1<List<String>> retOutput = evidenceTable.getSelectKeysByOwnerOutput(receipt);
            List<String> keys = retOutput.getValue1();

            for (String key : keys) {
                evidences.add(this.getEvidence(key));
            }
        } catch (Exception e) {
            logger.error(" getEvidencesByOwner exception, error message is {}", e.getMessage());
            System.out.printf(" getEvidencesByOwner account failed, error message is %s\n", e.getMessage());
        }
        return evidences;
    }


}
